home *** CD-ROM | disk | FTP | other *** search
/ One Click 11 / OneClick11.iso / Bancos de Dados / Conversao / Mysql2Excel / Setup.exe / Mysql2Excel.exe / threading.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2003-06-23  |  29.8 KB  |  791 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.2)
  3.  
  4. """Proposed new threading module, emulating a subset of Java's threading model."""
  5. import sys
  6. import time
  7. import thread
  8. import traceback
  9. import StringIO
  10. _sys = sys
  11. del sys
  12. _time = time.time
  13. _sleep = time.sleep
  14. del time
  15. _start_new_thread = thread.start_new_thread
  16. _allocate_lock = thread.allocate_lock
  17. _get_ident = thread.get_ident
  18. ThreadError = thread.error
  19. del thread
  20. _print_exc = traceback.print_exc
  21. del traceback
  22. _StringIO = StringIO.StringIO
  23. del StringIO
  24. _VERBOSE = 0
  25. if __debug__:
  26.     
  27.     class _Verbose:
  28.         
  29.         def __init__(self, verbose = None):
  30.             if verbose is None:
  31.                 verbose = _VERBOSE
  32.             
  33.             self._Verbose__verbose = verbose
  34.  
  35.         
  36.         def _note(self, format, *args):
  37.             if self._Verbose__verbose:
  38.                 format = format % args
  39.                 format = '%s: %s\n' % (currentThread().getName(), format)
  40.                 _sys.stderr.write(format)
  41.             
  42.  
  43.  
  44. else:
  45.     
  46.     class _Verbose:
  47.         
  48.         def __init__(self, verbose = None):
  49.             pass
  50.  
  51.         
  52.         def _note(self, *args):
  53.             pass
  54.  
  55.  
  56. Lock = _allocate_lock
  57.  
  58. def RLock(*args, **kwargs):
  59.     return apply(_RLock, args, kwargs)
  60.  
  61.  
  62. class _RLock(_Verbose):
  63.     
  64.     def __init__(self, verbose = None):
  65.         _Verbose.__init__(self, verbose)
  66.         self._RLock__block = _allocate_lock()
  67.         self._RLock__owner = None
  68.         self._RLock__count = 0
  69.  
  70.     
  71.     def __repr__(self):
  72.         if self._RLock__owner:
  73.             pass
  74.         return '<%s(%s, %d)>' % (self.__class__.__name__, self._RLock__owner.getName(), self._RLock__count)
  75.  
  76.     
  77.     def acquire(self, blocking = 1):
  78.         me = currentThread()
  79.         if self._RLock__owner is me:
  80.             self._RLock__count = self._RLock__count + 1
  81.             if __debug__:
  82.                 self._note('%s.acquire(%s): recursive success', self, blocking)
  83.             
  84.             return 1
  85.         
  86.         rc = self._RLock__block.acquire(blocking)
  87.         if rc:
  88.             self._RLock__owner = me
  89.             self._RLock__count = 1
  90.             if __debug__:
  91.                 self._note('%s.acquire(%s): initial succes', self, blocking)
  92.             
  93.         elif __debug__:
  94.             self._note('%s.acquire(%s): failure', self, blocking)
  95.         
  96.         return rc
  97.  
  98.     
  99.     def release(self):
  100.         me = currentThread()
  101.         if not __debug__ and self._RLock__owner is me:
  102.             raise AssertionError, 'release() of un-acquire()d lock'
  103.         self._RLock__count = count = self._RLock__count - 1
  104.         if not count:
  105.             self._RLock__owner = None
  106.             self._RLock__block.release()
  107.             if __debug__:
  108.                 self._note('%s.release(): final release', self)
  109.             
  110.         elif __debug__:
  111.             self._note('%s.release(): non-final release', self)
  112.         
  113.  
  114.     
  115.     def _acquire_restore(self, .2):
  116.         (count, owner) = .2
  117.         self._RLock__block.acquire()
  118.         self._RLock__count = count
  119.         self._RLock__owner = owner
  120.         if __debug__:
  121.             self._note('%s._acquire_restore()', self)
  122.         
  123.  
  124.     
  125.     def _release_save(self):
  126.         if __debug__:
  127.             self._note('%s._release_save()', self)
  128.         
  129.         count = self._RLock__count
  130.         self._RLock__count = 0
  131.         owner = self._RLock__owner
  132.         self._RLock__owner = None
  133.         self._RLock__block.release()
  134.         return (count, owner)
  135.  
  136.     
  137.     def _is_owned(self):
  138.         return self._RLock__owner is currentThread()
  139.  
  140.  
  141.  
  142. def Condition(*args, **kwargs):
  143.     return apply(_Condition, args, kwargs)
  144.  
  145.  
  146. class _Condition(_Verbose):
  147.     
  148.     def __init__(self, lock = None, verbose = None):
  149.         _Verbose.__init__(self, verbose)
  150.         if lock is None:
  151.             lock = RLock()
  152.         
  153.         self._Condition__lock = lock
  154.         self.acquire = lock.acquire
  155.         self.release = lock.release
  156.         
  157.         try:
  158.             self._release_save = lock._release_save
  159.         except AttributeError:
  160.             pass
  161.  
  162.         
  163.         try:
  164.             self._acquire_restore = lock._acquire_restore
  165.         except AttributeError:
  166.             pass
  167.  
  168.         
  169.         try:
  170.             self._is_owned = lock._is_owned
  171.         except AttributeError:
  172.             pass
  173.  
  174.         self._Condition__waiters = []
  175.  
  176.     
  177.     def __repr__(self):
  178.         return '<Condition(%s, %d)>' % (self._Condition__lock, len(self._Condition__waiters))
  179.  
  180.     
  181.     def _release_save(self):
  182.         self._Condition__lock.release()
  183.  
  184.     
  185.     def _acquire_restore(self, x):
  186.         self._Condition__lock.acquire()
  187.  
  188.     
  189.     def _is_owned(self):
  190.         if self._Condition__lock.acquire(0):
  191.             self._Condition__lock.release()
  192.             return 0
  193.         else:
  194.             return 1
  195.  
  196.     
  197.     def wait(self, timeout = None):
  198.         me = currentThread()
  199.         if not __debug__ and self._is_owned():
  200.             raise AssertionError, 'wait() of un-acquire()d lock'
  201.         waiter = _allocate_lock()
  202.         waiter.acquire()
  203.         self._Condition__waiters.append(waiter)
  204.         saved_state = self._release_save()
  205.         
  206.         try:
  207.             if timeout is None:
  208.                 waiter.acquire()
  209.                 if __debug__:
  210.                     self._note('%s.wait(): got it', self)
  211.                 
  212.             else:
  213.                 endtime = _time() + timeout
  214.                 delay = 0.00050000000000000001
  215.                 while 1:
  216.                     gotit = waiter.acquire(0)
  217.                     if gotit:
  218.                         break
  219.                     
  220.                     remaining = endtime - _time()
  221.                     if remaining <= 0:
  222.                         break
  223.                     
  224.                     delay = min(delay * 2, remaining, 0.050000000000000003)
  225.                     _sleep(delay)
  226.                 if not gotit:
  227.                     if __debug__:
  228.                         self._note('%s.wait(%s): timed out', self, timeout)
  229.                     
  230.                     
  231.                     try:
  232.                         self._Condition__waiters.remove(waiter)
  233.                     except ValueError:
  234.                         pass
  235.  
  236.                 elif __debug__:
  237.                     self._note('%s.wait(%s): got it', self, timeout)
  238.                 self._acquire_restore(saved_state)
  239.                 return None
  240.  
  241.  
  242.     
  243.     def notify(self, n = 1):
  244.         me = currentThread()
  245.         if not __debug__ and self._is_owned():
  246.             raise AssertionError, 'notify() of un-acquire()d lock'
  247.         _Condition__waiters = self._Condition__waiters
  248.         waiters = _Condition__waiters[:n]
  249.         if not waiters:
  250.             if __debug__:
  251.                 self._note('%s.notify(): no waiters', self)
  252.             
  253.             return None
  254.         
  255.         if not n != 1 and 's':
  256.             pass
  257.         self._note('%s.notify(): notifying %d waiter%s', self, n, '')
  258.         for waiter in waiters:
  259.             waiter.release()
  260.             
  261.             try:
  262.                 _Condition__waiters.remove(waiter)
  263.             except ValueError:
  264.                 pass
  265.  
  266.         
  267.  
  268.     
  269.     def notifyAll(self):
  270.         self.notify(len(self._Condition__waiters))
  271.  
  272.  
  273.  
  274. def Semaphore(*args, **kwargs):
  275.     return apply(_Semaphore, args, kwargs)
  276.  
  277.  
  278. class _Semaphore(_Verbose):
  279.     
  280.     def __init__(self, value = 1, verbose = None):
  281.         if not __debug__ and value >= 0:
  282.             raise AssertionError, 'Semaphore initial value must be >= 0'
  283.         _Verbose.__init__(self, verbose)
  284.         self._Semaphore__cond = Condition(Lock())
  285.         self._Semaphore__value = value
  286.  
  287.     
  288.     def acquire(self, blocking = 1):
  289.         rc = 0
  290.         self._Semaphore__cond.acquire()
  291.         while self._Semaphore__value == 0:
  292.             if not blocking:
  293.                 break
  294.             
  295.             if __debug__:
  296.                 self._note('%s.acquire(%s): blocked waiting, value=%s', self, blocking, self._Semaphore__value)
  297.             
  298.             self._Semaphore__cond.wait()
  299.         self._Semaphore__value = self._Semaphore__value - 1
  300.         if __debug__:
  301.             self._note('%s.acquire: success, value=%s', self, self._Semaphore__value)
  302.         
  303.         rc = 1
  304.         self._Semaphore__cond.release()
  305.         return rc
  306.  
  307.     
  308.     def release(self):
  309.         self._Semaphore__cond.acquire()
  310.         self._Semaphore__value = self._Semaphore__value + 1
  311.         if __debug__:
  312.             self._note('%s.release: success, value=%s', self, self._Semaphore__value)
  313.         
  314.         self._Semaphore__cond.notify()
  315.         self._Semaphore__cond.release()
  316.  
  317.  
  318.  
  319. def BoundedSemaphore(*args, **kwargs):
  320.     return apply(_BoundedSemaphore, args, kwargs)
  321.  
  322.  
  323. class _BoundedSemaphore(_Semaphore):
  324.     '''Semaphore that checks that # releases is <= # acquires'''
  325.     
  326.     def __init__(self, value = 1, verbose = None):
  327.         _Semaphore.__init__(self, value, verbose)
  328.         self._initial_value = value
  329.  
  330.     
  331.     def release(self):
  332.         if self._Semaphore__value >= self._initial_value:
  333.             raise ValueError, 'Semaphore released too many times'
  334.         
  335.         return _Semaphore.release(self)
  336.  
  337.  
  338.  
  339. def Event(*args, **kwargs):
  340.     return apply(_Event, args, kwargs)
  341.  
  342.  
  343. class _Event(_Verbose):
  344.     
  345.     def __init__(self, verbose = None):
  346.         _Verbose.__init__(self, verbose)
  347.         self._Event__cond = Condition(Lock())
  348.         self._Event__flag = 0
  349.  
  350.     
  351.     def isSet(self):
  352.         return self._Event__flag
  353.  
  354.     
  355.     def set(self):
  356.         self._Event__cond.acquire()
  357.         self._Event__flag = 1
  358.         self._Event__cond.notifyAll()
  359.         self._Event__cond.release()
  360.  
  361.     
  362.     def clear(self):
  363.         self._Event__cond.acquire()
  364.         self._Event__flag = 0
  365.         self._Event__cond.release()
  366.  
  367.     
  368.     def wait(self, timeout = None):
  369.         self._Event__cond.acquire()
  370.         if not (self._Event__flag):
  371.             self._Event__cond.wait(timeout)
  372.         
  373.         self._Event__cond.release()
  374.  
  375.  
  376. _counter = 0
  377.  
  378. def _newname(template = 'Thread-%d'):
  379.     global _counter
  380.     _counter = _counter + 1
  381.     return template % _counter
  382.  
  383. _active_limbo_lock = _allocate_lock()
  384. _active = { }
  385. _limbo = { }
  386.  
  387. class Thread(_Verbose):
  388.     __initialized = 0
  389.     
  390.     def __init__(self, group = None, target = None, name = None, args = (), kwargs = { }, verbose = None):
  391.         if not __debug__ and group is None:
  392.             raise AssertionError, 'group argument must be None for now'
  393.         _Verbose.__init__(self, verbose)
  394.         self._Thread__target = target
  395.         if not name:
  396.             pass
  397.         self._Thread__name = str(_newname())
  398.         self._Thread__args = args
  399.         self._Thread__kwargs = kwargs
  400.         self._Thread__daemonic = self._set_daemon()
  401.         self._Thread__started = 0
  402.         self._Thread__stopped = 0
  403.         self._Thread__block = Condition(Lock())
  404.         self._Thread__initialized = 1
  405.  
  406.     
  407.     def _set_daemon(self):
  408.         return currentThread().isDaemon()
  409.  
  410.     
  411.     def __repr__(self):
  412.         if not __debug__ and self._Thread__initialized:
  413.             raise AssertionError, 'Thread.__init__() was not called'
  414.         status = 'initial'
  415.         if self._Thread__started:
  416.             status = 'started'
  417.         
  418.         if self._Thread__stopped:
  419.             status = 'stopped'
  420.         
  421.         if self._Thread__daemonic:
  422.             status = status + ' daemon'
  423.         
  424.         return '<%s(%s, %s)>' % (self.__class__.__name__, self._Thread__name, status)
  425.  
  426.     
  427.     def start(self):
  428.         if not __debug__ and self._Thread__initialized:
  429.             raise AssertionError, 'Thread.__init__() not called'
  430.         if not __debug__ and not (self._Thread__started):
  431.             raise AssertionError, 'thread already started'
  432.         if __debug__:
  433.             self._note('%s.start(): starting thread', self)
  434.         
  435.         _active_limbo_lock.acquire()
  436.         _limbo[self] = self
  437.         _active_limbo_lock.release()
  438.         _start_new_thread(self._Thread__bootstrap, ())
  439.         self._Thread__started = 1
  440.         _sleep(9.9999999999999995e-007)
  441.  
  442.     
  443.     def run(self):
  444.         if self._Thread__target:
  445.             apply(self._Thread__target, self._Thread__args, self._Thread__kwargs)
  446.         
  447.  
  448.     
  449.     def __bootstrap(self):
  450.         
  451.         try:
  452.             self._Thread__started = 1
  453.             _active_limbo_lock.acquire()
  454.             _active[_get_ident()] = self
  455.             del _limbo[self]
  456.             _active_limbo_lock.release()
  457.             if __debug__:
  458.                 self._note('%s.__bootstrap(): thread started', self)
  459.             
  460.             
  461.             try:
  462.                 self.run()
  463.             except SystemExit:
  464.                 if __debug__:
  465.                     self._note('%s.__bootstrap(): raised SystemExit', self)
  466.                 
  467.             except:
  468.                 __debug__
  469.                 if __debug__:
  470.                     self._note('%s.__bootstrap(): unhandled exception', self)
  471.                 
  472.                 s = _StringIO()
  473.                 _print_exc(file = s)
  474.                 _sys.stderr.write('Exception in thread %s:\n%s\n' % (self.getName(), s.getvalue()))
  475.  
  476.             if __debug__:
  477.                 self._note('%s.__bootstrap(): normal return', self)
  478.         finally:
  479.             self._Thread__stop()
  480.             
  481.             try:
  482.                 self._Thread__delete()
  483.             except:
  484.                 pass
  485.  
  486.  
  487.  
  488.     
  489.     def __stop(self):
  490.         self._Thread__block.acquire()
  491.         self._Thread__stopped = 1
  492.         self._Thread__block.notifyAll()
  493.         self._Thread__block.release()
  494.  
  495.     
  496.     def __delete(self):
  497.         _active_limbo_lock.acquire()
  498.         del _active[_get_ident()]
  499.         _active_limbo_lock.release()
  500.  
  501.     
  502.     def join(self, timeout = None):
  503.         if not __debug__ and self._Thread__initialized:
  504.             raise AssertionError, 'Thread.__init__() not called'
  505.         if not __debug__ and self._Thread__started:
  506.             raise AssertionError, 'cannot join thread before it is started'
  507.         if not __debug__ and self is not currentThread():
  508.             raise AssertionError, 'cannot join current thread'
  509.         if __debug__:
  510.             if not (self._Thread__stopped):
  511.                 self._note('%s.join(): waiting until thread stops', self)
  512.             
  513.         
  514.         self._Thread__block.acquire()
  515.         if timeout is None:
  516.             while not (self._Thread__stopped):
  517.                 self._Thread__block.wait()
  518.             if __debug__:
  519.                 self._note('%s.join(): thread stopped', self)
  520.             
  521.         else:
  522.             deadline = _time() + timeout
  523.             while not (self._Thread__stopped):
  524.                 delay = deadline - _time()
  525.                 if delay <= 0:
  526.                     if __debug__:
  527.                         self._note('%s.join(): timed out', self)
  528.                     
  529.                     break
  530.                 
  531.                 self._Thread__block.wait(delay)
  532.             if __debug__:
  533.                 self._note('%s.join(): thread stopped', self)
  534.             
  535.         self._Thread__block.release()
  536.  
  537.     
  538.     def getName(self):
  539.         if not __debug__ and self._Thread__initialized:
  540.             raise AssertionError, 'Thread.__init__() not called'
  541.         return self._Thread__name
  542.  
  543.     
  544.     def setName(self, name):
  545.         if not __debug__ and self._Thread__initialized:
  546.             raise AssertionError, 'Thread.__init__() not called'
  547.         self._Thread__name = str(name)
  548.  
  549.     
  550.     def isAlive(self):
  551.         if not __debug__ and self._Thread__initialized:
  552.             raise AssertionError, 'Thread.__init__() not called'
  553.         if self._Thread__started:
  554.             pass
  555.         return not (self._Thread__stopped)
  556.  
  557.     
  558.     def isDaemon(self):
  559.         if not __debug__ and self._Thread__initialized:
  560.             raise AssertionError, 'Thread.__init__() not called'
  561.         return self._Thread__daemonic
  562.  
  563.     
  564.     def setDaemon(self, daemonic):
  565.         if not __debug__ and self._Thread__initialized:
  566.             raise AssertionError, 'Thread.__init__() not called'
  567.         if not __debug__ and not (self._Thread__started):
  568.             raise AssertionError, 'cannot set daemon status of active thread'
  569.         self._Thread__daemonic = daemonic
  570.  
  571.  
  572.  
  573. def Timer(*args, **kwargs):
  574.     return _Timer(*args, **kwargs)
  575.  
  576.  
  577. class _Timer(Thread):
  578.     """Call a function after a specified number of seconds:
  579.  
  580.     t = Timer(30.0, f, args=[], kwargs={})
  581.     t.start()
  582.     t.cancel() # stop the timer's action if it's still waiting
  583.     """
  584.     
  585.     def __init__(self, interval, function, args = [], kwargs = { }):
  586.         Thread.__init__(self)
  587.         self.interval = interval
  588.         self.function = function
  589.         self.args = args
  590.         self.kwargs = kwargs
  591.         self.finished = Event()
  592.  
  593.     
  594.     def cancel(self):
  595.         """Stop the timer if it hasn't finished yet"""
  596.         self.finished.set()
  597.  
  598.     
  599.     def run(self):
  600.         self.finished.wait(self.interval)
  601.         if not self.finished.isSet():
  602.             self.function(*self.args, **self.kwargs)
  603.         
  604.         self.finished.set()
  605.  
  606.  
  607.  
  608. class _MainThread(Thread):
  609.     
  610.     def __init__(self):
  611.         Thread.__init__(self, name = 'MainThread')
  612.         self._Thread__started = 1
  613.         _active_limbo_lock.acquire()
  614.         _active[_get_ident()] = self
  615.         _active_limbo_lock.release()
  616.         import atexit
  617.         atexit.register(self._MainThread__exitfunc)
  618.  
  619.     
  620.     def _set_daemon(self):
  621.         return 0
  622.  
  623.     
  624.     def _MainThread__exitfunc(self):
  625.         self._Thread__stop()
  626.         t = _pickSomeNonDaemonThread()
  627.         if t:
  628.             if __debug__:
  629.                 self._note('%s: waiting for other threads', self)
  630.             
  631.         
  632.         while t:
  633.             t.join()
  634.             t = _pickSomeNonDaemonThread()
  635.         if __debug__:
  636.             self._note('%s: exiting', self)
  637.         
  638.         self._Thread__delete()
  639.  
  640.  
  641.  
  642. def _pickSomeNonDaemonThread():
  643.     for t in enumerate():
  644.         if not t.isDaemon() and t.isAlive():
  645.             return t
  646.         
  647.     
  648.     return None
  649.  
  650.  
  651. class _DummyThread(Thread):
  652.     
  653.     def __init__(self):
  654.         Thread.__init__(self, name = _newname('Dummy-%d'))
  655.         self._Thread__started = 1
  656.         _active_limbo_lock.acquire()
  657.         _active[_get_ident()] = self
  658.         _active_limbo_lock.release()
  659.  
  660.     
  661.     def _set_daemon(self):
  662.         return 1
  663.  
  664.     
  665.     def join(self, timeout = None):
  666.         if not __debug__ and 0:
  667.             raise AssertionError, 'cannot join a dummy thread'
  668.  
  669.  
  670.  
  671. def currentThread():
  672.     
  673.     try:
  674.         return _active[_get_ident()]
  675.     except KeyError:
  676.         return _DummyThread()
  677.  
  678.  
  679.  
  680. def activeCount():
  681.     _active_limbo_lock.acquire()
  682.     count = len(_active) + len(_limbo)
  683.     _active_limbo_lock.release()
  684.     return count
  685.  
  686.  
  687. def enumerate():
  688.     _active_limbo_lock.acquire()
  689.     active = _active.values() + _limbo.values()
  690.     _active_limbo_lock.release()
  691.     return active
  692.  
  693. _MainThread()
  694.  
  695. def _test():
  696.     
  697.     class BoundedQueue(_Verbose):
  698.         
  699.         def __init__(self, limit):
  700.             _Verbose.__init__(self)
  701.             self.mon = RLock()
  702.             self.rc = Condition(self.mon)
  703.             self.wc = Condition(self.mon)
  704.             self.limit = limit
  705.             self.queue = []
  706.  
  707.         
  708.         def put(self, item):
  709.             self.mon.acquire()
  710.             while len(self.queue) >= self.limit:
  711.                 self._note('put(%s): queue full', item)
  712.                 self.wc.wait()
  713.             self.queue.append(item)
  714.             self._note('put(%s): appended, length now %d', item, len(self.queue))
  715.             self.rc.notify()
  716.             self.mon.release()
  717.  
  718.         
  719.         def get(self):
  720.             self.mon.acquire()
  721.             while not (self.queue):
  722.                 self._note('get(): queue empty')
  723.                 self.rc.wait()
  724.             item = self.queue[0]
  725.             del self.queue[0]
  726.             self._note('get(): got %s, %d left', item, len(self.queue))
  727.             self.wc.notify()
  728.             self.mon.release()
  729.             return item
  730.  
  731.  
  732.     
  733.     class ProducerThread(Thread):
  734.         
  735.         def __init__(self, queue, quota):
  736.             Thread.__init__(self, name = 'Producer')
  737.             self.queue = queue
  738.             self.quota = quota
  739.  
  740.         
  741.         def run(self):
  742.             random = random
  743.             import random
  744.             counter = 0
  745.             while counter < self.quota:
  746.                 counter = counter + 1
  747.                 self.queue.put('%s.%d' % (self.getName(), counter))
  748.                 _sleep(random() * 1.0000000000000001e-005)
  749.  
  750.  
  751.     
  752.     class ConsumerThread(Thread):
  753.         
  754.         def __init__(self, queue, count):
  755.             Thread.__init__(self, name = 'Consumer')
  756.             self.queue = queue
  757.             self.count = count
  758.  
  759.         
  760.         def run(self):
  761.             while self.count > 0:
  762.                 item = self.queue.get()
  763.                 print item
  764.                 self.count = self.count - 1
  765.  
  766.  
  767.     NP = 3
  768.     QL = 4
  769.     NI = 5
  770.     Q = BoundedQueue(QL)
  771.     P = []
  772.     for i in range(NP):
  773.         t = ProducerThread(Q, NI)
  774.         t.setName('Producer-%d' % (i + 1))
  775.         P.append(t)
  776.     
  777.     C = ConsumerThread(Q, NI * NP)
  778.     for t in P:
  779.         t.start()
  780.         _sleep(9.9999999999999995e-007)
  781.     
  782.     C.start()
  783.     for t in P:
  784.         t.join()
  785.     
  786.     C.join()
  787.  
  788. if __name__ == '__main__':
  789.     _test()
  790.  
  791.